﻿//using System;
//using System.Collections.Generic;
//using System.Linq;
//using System.Text;
//using System.Threading.Tasks;
//using Unit = System.UInt32;

//namespace ArgusPCLib.Mathematics
//{
//	public class Decimal : BigNumBase
//	{
//		#region Fields
//		static int standardFractionBits = 2 * Decimal.UnitSize;
//		#endregion

//		#region Constructors
//		static Decimal() { Decimal.Table = new LookUpTable(); }

//		private Decimal(NumberProperties properties, List<Unit> bits, int fractionBits)
//			: base(properties, bits)
//		{
//			this.FractionBits = fractionBits;
//			this.RemoveTrailingZeros();
//		}

//		private Decimal(bool isNegative, List<Unit> bits, int fractionBits)
//			: base(isNegative, false, bits)
//		{
//			this.FractionBits = fractionBits;
//			this.RemoveTrailingZeros();
//		}

//		public Decimal(Decimal d)
//			: this(d.GetBits()) { }

//		public Decimal(int[] bits)
//			: base(bits.Subarray(0, bits.Length - 1))
//		{
//			this.FractionBits = bits.Last();
//			this.RemoveLeadingZeros();
//		}

//		public Decimal()
//			: this(NumberProperties.None, new List<Unit>(), 0) { }
//		#endregion

//		#region Properties
//		public static LookUpTable Table { get; set; }
//		public static Decimal Zero
//		{
//			get
//			{
//				if (Decimal.Table != null)
//					return Decimal.Table.Zero;
//				return new Decimal(false, new List<Unit>(new Unit[] { 0 }), 0);
//			}
//		}
//		public static Decimal One
//		{
//			get
//			{
//				if (Decimal.Table != null)
//					return Decimal.Table.One;
//				return new Decimal(false, new List<Unit>(new Unit[] { 1 }), 0);
//			}
//		}
//		public static Decimal NaN
//		{
//			get
//			{
//				if (Decimal.Table != null)
//					return Decimal.Table.NaN;
//				Decimal i = new Decimal();
//				i.SetToNaN();
//				return i;
//			}
//		}
//		public static Decimal PositiveInfinity
//		{
//			get
//			{
//				if (Decimal.Table != null)
//					return Decimal.Table.PositiveInfinity;
//				Decimal i = 0;
//				i.SetToInfinite();
//				return i;
//			}
//		}
//		public static Decimal NegativeInfinity
//		{
//			get
//			{
//				if (Decimal.Table != null)
//					return Decimal.Table.NegativeInfinity;
//				Decimal i = -1;
//				i.SetToInfinite();
//				return i;
//			}
//		}

//		/// <summary>
//		/// The standard maximal value for <see cref="Decimal.FractionDigits"/>
//		/// for operations, e.g. a division, which could prodece a decimal with
//		/// an fractional part of infinite length and thus require a limit.
//		/// </summary>
//		public static int StandardFractionBits
//		{
//			get { return Decimal.standardFractionBits; }
//			set
//			{
//				if (value < 0)
//					throw new ArgumentOutOfRangeException();
//				Decimal.standardFractionBits = value;
//			}
//		}

//		/// <summary>
//		/// The number of bits used to describe the fractional part of the
//		/// <see cref="Decimal"/>. This value is equivalent to the position
//		/// of the decimal point in a binary number system.
//		/// </summary>
//		public int FractionBits { get; private set; }
//		#endregion

//		#region Protected Methods
//		protected override void SetToInfinite()
//		{
//			base.SetToInfinite();
//			this.FractionBits = 0;
//		}

//		protected override void SetToNaN()
//		{
//			base.SetToNaN();
//			this.FractionBits = 0;
//		}

//		protected override void SetToZero()
//		{
//			base.SetToZero();
//			this.FractionBits = 0;
//		}
//		#endregion

//		#region Private Methods
//		private void RemoveTrailingZeros()
//		{
//			while (this.FractionBits >= Decimal.UnitSize && this[0] == 0)
//			{
//				base.ShiftRight(Decimal.UnitSize);
//				this.FractionBits -= Decimal.UnitSize;
//			}
//			while (this.FractionBits > 0 && (this[0] & 1) == 0)
//			{
//				base.ShiftRight(1);
//				this.FractionBits--;
//			}
//		}

//		private void ShiftLeftD(int count)
//		{
//			int shift = System.Math.Min(this.FractionBits, count);
//			this.FractionBits -= shift;
//			shift = count - shift;
//			if (shift > 0)
//				base.ShiftLeft(shift);
//		}

//		private void ShiftRightD(int count)
//		{
//			if (this.FractionBits == 0)
//			{
//				while (count > 0 && (this[0] & 1) == 0)
//				{
//					base.ShiftRight(1);
//					count--;
//				}
//			}
//			this.FractionBits += count;
//		}

//		private void AddD(Decimal d)
//		{
//			int shift = System.Math.Max(this.FractionBits, d.FractionBits);
//			this.ShiftLeftD(shift);
//			d.ShiftLeftD(shift);
//			base.Add(d);
//			d.ShiftRightD(shift);
//			if (!this._IsInfinite && !this._IsNaN)
//			{
//				this.ShiftRightD(shift);
//				this.RemoveTrailingZeros();
//			}
//		}

//		private void SubtractD(Decimal d)
//		{
//			int shift = System.Math.Max(this.FractionBits, d.FractionBits);
//			this.ShiftLeftD(shift);
//			d.ShiftLeftD(shift);
//			base.Subtract(d);
//			d.ShiftRightD(shift);
//			if (!this._IsInfinite && !this._IsNaN)
//			{
//				this.ShiftRightD(shift);
//				this.RemoveTrailingZeros();
//			}
//		}

//		private void MultiplyD(Decimal d)
//		{
//			base.Multiply(d);
//			if (!this._IsInfinite && !this._IsNaN)
//			{
//				this.FractionBits += d.FractionBits;
//				this.RemoveTrailingZeros();
//			}
//		}

//		private void DivideD(Decimal d, int maxFractionBits)
//		{
//			maxFractionBits = System.Math.Max(0, maxFractionBits);
//			int shift = System.Math.Max(this.FractionBits, d.FractionBits);
//			this.ShiftLeftD(shift + maxFractionBits);
//			d.ShiftLeftD(shift);
//			//base.ShiftLeft(maxFractionBits);
//			BigNumBase r;
//			base.Divide(d, out r);
//			d.ShiftRightD(shift);
//			if (!this._IsInfinite && !this._IsNaN)
//			{
//				this.ShiftRightD(maxFractionBits);
//				this.RemoveTrailingZeros();
//			}
//		}
//		#endregion

//		#region Public Methods
//		public override int[] GetBits()
//		{
//			List<int> RetVal = new List<int>(base.GetBits());
//			RetVal.Add(this.FractionBits);
//			return RetVal.ToArray();
//		}
//		#endregion

//		#region ToString


//		#endregion

//		#region Static Methods
//		public static Decimal Negate(Decimal d)
//		{
//			int[] bits = d.GetBits();
//			Flags<NumberProperties> props = Flags<NumberProperties>.FromEnum((NumberProperties)bits[bits.Length - 2]);
//			if (props.HasFlag(NumberProperties.IsNegative) == false)
//				return d;

//			bits[bits.Length - 2] = (int)props.SetFlag(NumberProperties.IsNegative, false);
//			return new Decimal(bits);
//		}

//		public static Decimal Truncate(Decimal d, int fractionBits)
//		{
//			if (fractionBits < 0)
//				throw new ArgumentOutOfRangeException("fractionBits", "Must not be negative.");
//			Decimal RetVal = new Decimal(d);
//			if (RetVal.FractionBits > fractionBits)
//			{
//				RetVal.ShiftRight(RetVal.FractionBits - fractionBits);
//				RetVal.FractionBits = fractionBits;
//			}
//			return RetVal;
//		}

//		public static Decimal Divide(Decimal dividend, Decimal divisor, int maxFractionBits)
//		{
//			Decimal RetVal = new Decimal(dividend);
//			RetVal.DivideD(divisor, maxFractionBits);
//			return RetVal;
//		}

//		public static Decimal Lb(Decimal d)
//		{
//			return Decimal.Lb(d, Decimal.StandardFractionBits);
//		}

//		public static Decimal Lb(Decimal d, int maxFractionBits)
//		{
//			if (d._IsNaN)
//				return Decimal.NaN;
//			if (d._IsNegative)
//				return Decimal.NaN;
//			if (d == Decimal.Zero)
//				return Decimal.NegativeInfinity;
//			if (d == 1)
//				return Decimal.Zero;

//			int n = d.Units * Decimal.UnitSize - 1;
//			while (n > -1 && d.GetBit(n) == false)
//				n--;
//			n -= d.FractionBits;

//			Decimal RetVal = (Integer)n;
//			d = new Decimal(d);
//			if (n > 0)
//				d.ShiftRightD(n);
//			else if (n < 0)
//				d.ShiftLeftD(-n);

//			int bitIndex = d.FractionBits + 2;
//			int index = bitIndex / Decimal.UnitSize;
//			int mask = 1 << (bitIndex % Decimal.UnitSize);

//			for (int i = 0; i < maxFractionBits; i++)
//			{
//				d.MultiplyD(d);
//				if ((d[index] & mask) == 1)
//				{
//					d.ShiftRightD(1);
//					RetVal.InsertLeft(true);
//				}
//				else
//				{
//					RetVal.InsertLeft(false);
//				}
//			}
//			RetVal.FractionBits = maxFractionBits;
//			RetVal.RemoveTrailingZeros();
//			return RetVal;
//		}

//		public static Decimal Log(Decimal x, Decimal b)
//		{
//			return Decimal.Log(x, b, Decimal.StandardFractionBits);
//		}

//		public static Decimal Log(Decimal x, Decimal b, int maxFractionBits)
//		{
//			if (b._IsNegative || b == Decimal.Zero)
//				throw new InvalidOperationException("The base b must be positive.");
//			if (x._IsNaN)
//				return Decimal.NaN;
//			if (x._IsNegative)
//				return Decimal.NaN;
//			if (x == Decimal.Zero)
//				return Decimal.NegativeInfinity;
//			if (x == 1)
//				return Decimal.Zero;

//			Decimal lbX = Decimal.Lb(x, maxFractionBits);
//			Decimal lbB = Decimal.Lb(b, maxFractionBits);
//			lbX.DivideD(lbB, maxFractionBits);
//			return lbX;
//		}

//		public static Decimal Power(Decimal b, int e)
//		{
//			//Decimal E;
//			//if (e == 0)
//			//	return 1;

//			//if (e > 0)
//			//	E = e;
//			//else
//			//	E = Decimal.Negate(e);

//			Decimal result = 1;
//			Decimal a = new Decimal(b);
//			uint E = (uint)System.Math.Abs(e);

//			while (E > 0)
//			{
//				if ((E & 1) == 1)
//					result.MultiplyD(a);
//				a.MultiplyD(a);
//				E >>= 1;
//			}

//			if (e < 0)
//				return 1 / result;
//			else
//				return result;
//		}
//		#endregion

//		#region Operators
//		public static bool operator ==(Decimal a, Decimal b)
//		{
//			if (object.ReferenceEquals(a, null) || object.ReferenceEquals(b, null))
//				return object.ReferenceEquals(a, b);
//			if (a.FractionBits != b.FractionBits)
//				return false;
//			return a.IsEqualTo(b);
//		}

//		public static bool operator !=(Decimal a, Decimal b)
//		{
//			return !(a == b);
//		}

//		public static bool operator <(Decimal a, Decimal b)
//		{
//			int shift = System.Math.Max(a.FractionBits, b.FractionBits);
//			a.ShiftLeftD(shift);
//			b.ShiftLeftD(shift);
//			bool RetVal = a.IsSmallerThan(b);
//			a.ShiftRightD(shift);
//			b.ShiftRightD(shift);
//			return RetVal;
//		}

//		public static bool operator >(Decimal a, Decimal b)
//		{
//			int shift = System.Math.Max(a.FractionBits, b.FractionBits);
//			a.ShiftLeftD(shift);
//			b.ShiftLeftD(shift);
//			bool RetVal = a.IsGreaterThan(b);
//			a.ShiftRightD(shift);
//			b.ShiftRightD(shift);
//			return RetVal;
//		}

//		public static bool operator <=(Decimal a, Decimal b)
//		{
//			return (a < b || a == b);
//		}

//		public static bool operator >=(Decimal a, Decimal b)
//		{
//			return (a > b || a == b);
//		}

//		public static Decimal operator +(Decimal a, Decimal b)
//		{
//			Decimal RetVal = new Decimal(a);
//			RetVal.AddD(b);
//			return RetVal;
//		}

//		public static Decimal operator -(Decimal a, Decimal b)
//		{
//			Decimal RetVal = new Decimal(a);
//			RetVal.SubtractD(b);
//			return RetVal;
//		}

//		public static Decimal operator *(Decimal a, Decimal b)
//		{
//			Decimal RetVal = new Decimal(a);
//			RetVal.MultiplyD(b);
//			return RetVal;
//		}

//		public static Decimal operator /(Decimal a, Decimal b)
//		{
//			return Decimal.Divide(a, b, Decimal.StandardFractionBits);
//		}
//		#endregion

//		#region Implicit Casts
//		public static implicit operator Decimal(int i)
//		{
//			if (i == 0)
//				return Decimal.Zero;
//			if (i == 1)
//				return Decimal.One;
//			List<Unit> bits = new List<Unit>();
//			bits.Add((Unit)System.Math.Abs(i));
//			return new Decimal(i < 0, bits, 0);
//		}

//		public static implicit operator Decimal(uint i)
//		{
//			if (i == 0u)
//				return Decimal.Zero;
//			if (i == 1u)
//				return Decimal.One;
//			List<Unit> bits = new List<Unit>();
//			bits.Add(i);
//			return new Decimal(false, bits, 0);
//		}

//		public static implicit operator Decimal(long l)
//		{
//			if (l == 0L)
//				return Decimal.Zero;
//			if (l == 1L)
//				return Decimal.One;
//			List<Unit> bits = new List<Unit>();
//			ulong u = (ulong)System.Math.Abs(l);
//			bits.Add((uint)u);
//			bits.Add((uint)(u >> 32));
//			return new Decimal(l < 0, bits, 0);
//		}

//		public static implicit operator Decimal(ulong l)
//		{
//			if (l == 0UL)
//				return Decimal.Zero;
//			if (l == 1UL)
//				return Decimal.One;
//			List<Unit> bits = new List<Unit>();
//			bits.Add((uint)l);
//			bits.Add((uint)(l >> 32));
//			return new Decimal(false, bits, 0);
//		}

//		public static implicit operator Decimal(Integer i)
//		{
//			List<int> bits = new List<int>(i.GetBits());
//			bits.Add(0);
//			return new Decimal(bits.ToArray());
//		}
//		#endregion

//		#region Explicit Casts
//		public static explicit operator Integer(Decimal d)
//		{
//			if (d._IsNaN)
//				return null;
//			if (d._IsInfinite)
//			{
//				if (d._IsNegative)
//					return null;
//				else
//					return null;
//			}
//			else
//			{
//				int[] bits = d.GetBits();
//				Integer RetVal = new Integer(bits.Subarray(0, bits.Length - 1));
//				if (d.FractionBits > 0)
//					RetVal = RetVal >> d.FractionBits;
//				return RetVal;
//			}
//		}
//		#endregion

//		#region ILinearScalar
//		protected override IScalar AddCore(IScalar scalar)
//		{
//			return (this + (Decimal)scalar);
//		}

//		protected override IScalar DivideCore(IScalar scalar)
//		{
//			return (this / (Decimal)scalar);
//		}

//		protected override IScalar GetCopyCore()
//		{
//			return new Decimal(this);
//		}

//		public override bool Equals(object obj)
//		{
//			Decimal integer = obj as Decimal;
//			if (integer == null)
//				return false;
//			return this.IsEqualToCore(integer);
//		}

//		protected override bool IsEqualToCore(IScalar scalar)
//		{
//			return (this == (Decimal)scalar);
//		}

//		protected override bool IsGreaterThanCore(ILinearScalar scalar)
//		{
//			return (this > (Decimal)scalar);
//		}

//		protected override bool IsSmallerThanCore(ILinearScalar scalar)
//		{
//			return (this < (Decimal)scalar);
//		}

//		protected override IScalar MultiplyCore(IScalar scalar)
//		{
//			return (this * (Decimal)scalar);
//		}

//		protected override IScalar SubtractCore(IScalar scalar)
//		{
//			return (this - (Decimal)scalar);
//		}
//		#endregion

//		#region Subtypes
//		public sealed class LookUpTable
//		{
//			Decimal zero;
//			Decimal one;
//			Decimal nan;
//			Decimal positiveInfinity;
//			Decimal negativeInfinity;

//			public Decimal Zero
//			{
//				get
//				{
//					if (this.zero == null)
//						this.zero = new Decimal(false, new List<Unit>(new Unit[] { 0 }), 0);
//					return this.zero;
//				}
//			}
//			public Decimal One
//			{
//				get
//				{
//					if (this.one == null)
//						this.one = new Decimal(false, new List<Unit>(new Unit[] { 1 }), 0);
//					return this.one;
//				}
//			}
//			public Decimal NaN
//			{
//				get
//				{
//					if (this.nan == null)
//					{
//						this.nan = new Decimal();
//						this.nan.SetToNaN();
//					}
//					return this.nan;
//				}
//			}
//			public Decimal PositiveInfinity
//			{
//				get
//				{
//					if (this.positiveInfinity == null)
//					{
//						this.positiveInfinity = 0;
//						this.positiveInfinity.SetToInfinite();
//					}
//					return this.positiveInfinity;
//				}
//			}
//			public Decimal NegativeInfinity
//			{
//				get
//				{
//					if (this.negativeInfinity == null)
//					{
//						this.negativeInfinity = -1;
//						this.negativeInfinity.SetToInfinite();
//					}
//					return this.negativeInfinity;
//				}
//			}
//		}
//		#endregion
//	}
//}
